package graph;


/**
 * Represents a simple Edge object for a graph.
 * @author Alex Dusenbery
 * @version 1.0
 *
 */
@SuppressWarnings("rawtypes")
public class Edge<V, W> implements Comparable{
	
	private boolean directed;
	private W weight;
	
	/**
	 * The "from" vertex.
	 */
	private Vertex<V> v1;
	
	public Vertex<V> getV1() {
		return v1;
	}

	public void setV1(Vertex<V> v1) {
		this.v1 = v1;
	}

	/**
	 * The "to" vertex.
	 */
	private Vertex<V> v2;
	
	public Vertex<V> getV2() {
		return v2;
	}

	public void setV2(Vertex<V> v2) {
		this.v2 = v2;
	}
	/**
	 * Creates a new edge with the end-points specified.
	 * @param from
	 * @param to
	 */
	public Edge(Vertex<V> from, Vertex<V> to) {
		v1 = from;
		v2 = to;
		try {
			v1.putEdge(this);
			v2.putEdge(this);
		} catch (Exception e) {
			// TODO: handle exception
		}
		directed = false;
	}
	
	/**
	 * Creates a new edge
	 * @param from 
	 * @param to
	 * @param directed Whether this edge should be treated as a directed edge.
	 */
	public Edge(Vertex<V> from, Vertex<V> to, boolean directed) {
		v1 = from;
		v2 = to;
		try {
			v1.putEdge(this);
			v2.putEdge(this);
		} catch (Exception e) {
			// TODO: handle exception
		}
		this.directed = directed;
	}
	
	/**
	 * @return the isDirected
	 */
	public boolean isDirected() {
		return directed;
	}

	/**
	 * @param isDirected the isDirected to set
	 */
	public void setDirected(boolean isDirected) {
		this.directed = isDirected;
	}

	/**
	 * @return the weight
	 */
	public W getWeight() {
		return weight;
	}

	/**
	 * @param weight the weight to set
	 */
	public void setWeight(W weight) {
		this.weight = weight;
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append(v1.getName());
		sb.append(" -- ");
		sb.append(v2.getName());
		return sb.toString();
	}

	@SuppressWarnings("unchecked")
	@Override
	public int compareTo(Object arg0) {
		Edge that = (Edge) arg0;
		return ((Comparable) this.getWeight()).compareTo((W) that.getWeight());
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (directed ? 1231 : 1237);
		result = prime * result + ((v1 == null) ? 0 : v1.hashCode());
		result = prime * result + ((v2 == null) ? 0 : v2.hashCode());
		result = prime * result + ((weight == null) ? 0 : weight.hashCode());
		return result;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof Edge)) {
			return false;
		}
		Edge other = (Edge) obj;
		if (directed != other.directed) {
			return false;
		}
		if(v1 == null && v2 == null) {
			if(other.v1 != null && other.v2 != null)
				return false;
		}
		else if((v1 == null && v2 != null) || (v1 != null && v2 == null)) {
			if(!((other.v1 != null && other.v2 == null) || (other.v1 == null && other.v2 != null)))
				return false;
			else if(v1 == null) {
				if(other.v1 == null) {
					if(!v2.equals(other.v2))
						return false;
				}
				else if(other.v2 == null) {
					if(!v2.equals(other.v1))
						return false;
				}
			}
			else if(v2 == null) {
				if(other.v1 == null) {
					if(!v1.equals(other.v2))
						return false;
				}
				else if(other.v2 == null) {
					if(!v1.equals(other.v1))
						return false;
				}
			}
		}
		else if(!((v1.equals(other.v1) && v2.equals(other.v2)) 
				|| (v1.equals(other.v2)&& v2.equals(other.v1))))  
			return false;
//		if (v1 == null) {
//			if (other.v1 != null) {
//				return false;
//			}
//		} else if (!v1.equals(other.v1)) {
//			return false;
//		}
//		if (v2 == null) {
//			if (other.v2 != null) {
//				return false;
//			}
//		} else if (!v2.equals(other.v2)) {
//			return false;
//		}
		if (weight == null) {
			if (other.weight != null) {
				return false;
			}
		} else if (!weight.equals(other.weight)) {
			return false;
		}
		return true;
	}

}
